#pragma once

#include <libge/libge.h>
#include "ClientThread.h"
#include "ThreadChunks.h"
#include "ThreadGame.h"
#include "ThreadCtrl.h"
#include "ThreadRender.h"
#include "ThreadVisibility.h"
#include "ClientConnect.h"
#include "MainMenu.h"
#include "World.h"
#include "Player.h"
#include "InventoryWindow.h"

#define GL_MODE_FAST 0
#define GL_MODE_BASIC 1
#define GL_MODE_FULL 2

class Client {
public:
	Client();
	~Client();

	void LoadResources(char* path);
	void Solo();
	void Multiplayer();

	Player* getPlayer();
	World* getWorld();
	u64 getGameTicks();
	u64 getDayTicks();
	void setGameTicks(u64 t);
	void setDayTicks(u64 t);

	void setLevelType(const char* type);
	void setServerMode(int mode);
	void setCurrentDimension(int dim);
	void setDifficulty(int diff);
	void setMaxPlayers(int max);
	void addPlayerList(const char* name);
	void removePlayerList(const char* name);
	void setPlayerPing(const char* name, short ping);

	InventoryWindow* getInventoryWindow();
	
	ThreadChunks* getThreadChunks();
	ThreadGame* getThreadGame();
	ThreadCtrl* getThreadCtrl();
	ThreadVisibility* getThreadVisibility();
	ThreadRender* getThreadRender();
	ClientConnect* getClientConnect();
	
	struct {
		bool fullscreen;
		bool multicore;
		bool debug;
		int opengl_mode;
		int seed;
		int view_distance;
		int extended_view;
		int curr_view_dist;
		int vertex_size;
	} options;

	struct {
		// System
		ge_Renderer* render_base;
		ge_Shader* shader_base;
		ge_Shader* shader_lod;
		ge_Renderer* render_pick;
		ge_Shader* shader_pick;
		ge_Object* cube;
		ge_Object* stairs;
		ge_Object* rail;
		ge_Light* sun;
		int loc_wind;
		int loc_chunk_pos;
		int loc_global_illum;

		struct {
			ge_Renderer* render;
			ge_Shader* shader;
			std::vector<ge_Object*> steve;
		} entities;
	
		// Basic resources
		ge_Font* font;
		ge_Image* gui;
		ge_Image* terrain;

		// Mobs
		ge_Image* creeper;

		// Objects
		ge_Image* minecart;
	} res;

	ge_Keys* keys;
	ge_Camera* cam;

private:
	Player* player;
	World* world;
	MainMenu* menu;
	u64 gameTicks;
	u64 dayTicks;
	char* levelType;
	int serverMode;
	int currentDimension;
	int difficulty;
	int maxPlayers;
	char** playersList;
	int* playersPing;
	InventoryWindow* inventoryWindow;
	ClientThread* threadChunks;
	ClientThread* threadGame;
	ClientThread* threadCtrl;
	ClientThread* threadRender;
	ClientThread* threadVisibility;
	ClientConnect* connect;
};

extern "C" {
	float perlin_noise_2D(float vec[2], int terms, float freq, int seed);
};
